﻿//Copyright 2012 - Jonathan Allen

using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using Granite.Modeling;
using Granite.Modeling.Internals;

namespace Granite.Xaml
{
	/// <summary>
	/// Base class for view models. 
	/// </summary>
	public class ViewModelBase : SimpleModelBase
	{

		/// <summary>
		/// Returns an ICommand wrapped around the provided action.
		/// </summary>
		/// <param name="propertyName"></param>
		/// <param name="command"></param>
		/// <returns></returns>
		protected DelegateCommand GetCommand<T>(Action<T> command, [CallerMemberName] string propertyName)
		{
			if (command == null)
				throw new ArgumentNullException("command", "command is null.");
			if (propertyName == null)
				throw new ArgumentNullException("propertyName", "propertyName is null");
			if (String.IsNullOrEmpty(propertyName))
				throw new ArgumentException("propertyName is empty", "propertyName"); 
			Contract.EndContractBlock();

			if (!Properties.IsDefined(propertyName))
				Properties.Set(new DelegateCommand(p => command((T)p)), PropertySetModes.SetAsOriginal, propertyName);

			return Get<DelegateCommand>(propertyName);
		}

		/// <summary>
		/// Returns an ICommand wrapped around the provided action.
		/// </summary>
		/// <param name="propertyName"></param>
		/// <param name="command"></param>
		/// <returns></returns>
		protected DelegateCommand GetCommand(Action<object> command, [CallerMemberName] string propertyName)
		{
			if (command == null)
				throw new ArgumentNullException("command", "command is null.");
			if (propertyName == null)
				throw new ArgumentNullException("propertyName", "propertyName is null");
			if (String.IsNullOrEmpty(propertyName))
				throw new ArgumentException("propertyName is empty", "propertyName");
			Contract.EndContractBlock();

			if (!Properties.IsDefined(propertyName))
				Properties.Set(new DelegateCommand(command), PropertySetModes.SetAsOriginal, propertyName);

			return Get<DelegateCommand>(propertyName);
		}

		/// <summary>
		/// Returns an ICommand wrapped around the provided action.
		/// </summary>
		/// <param name="propertyName"></param>
		/// <param name="command"></param>
		/// <returns></returns>
		protected DelegateCommand GetCommand(Action command, [CallerMemberName] string propertyName)
		{
			if (command == null)
				throw new ArgumentNullException("command", "command is null.");
			if (propertyName == null)
				throw new ArgumentNullException("propertyName", "propertyName is null");
			if (String.IsNullOrEmpty(propertyName))
				throw new ArgumentException("propertyName is empty", "propertyName");
			Contract.EndContractBlock();

			if (!Properties.IsDefined(propertyName))
				Properties.Set(new DelegateCommand(command), PropertySetModes.SetAsOriginal, propertyName);

			return Get<DelegateCommand>(propertyName);
		}


		/// <summary>
		/// Returns an ICommand wrapped around the provided action.
		/// </summary>
		/// <param name="propertyName"></param>
		/// <param name="command"></param>
		/// <param name="canExecute"></param>
		/// <returns></returns>
		protected DelegateCommand GetCommand<T>(Action<T> command, Func<T, bool> canExecute, [CallerMemberName] string propertyName)
		{
			if (command == null)
				throw new ArgumentNullException("command", "command is null.");
			if (propertyName == null)
				throw new ArgumentNullException("propertyName", "propertyName is null");
			if (String.IsNullOrEmpty(propertyName))
				throw new ArgumentException("propertyName is empty", "propertyName");
			Contract.EndContractBlock();

			if (!Properties.IsDefined(propertyName))
				Properties.Set(new DelegateCommand(p => command((T)p), p => canExecute((T)p)), PropertySetModes.SetAsOriginal, propertyName);

			return Get<DelegateCommand>(propertyName);
		}

		/// <summary>
		/// Returns an ICommand wrapped around the provided action.
		/// </summary>
		/// <param name="propertyName"></param>
		/// <param name="command"></param>
		/// <param name="canExecute"></param>
		/// <returns></returns>
		protected DelegateCommand GetCommand(Action<object> command, Func<object, bool> canExecute, [CallerMemberName] string propertyName)
		{
			if (command == null)
				throw new ArgumentNullException("command", "command is null.");
			if (propertyName == null)
				throw new ArgumentNullException("propertyName", "propertyName is null");
			if (String.IsNullOrEmpty(propertyName))
				throw new ArgumentException("propertyName is empty", "propertyName");
			Contract.EndContractBlock();

			if (!Properties.IsDefined(propertyName))
				Properties.Set(new DelegateCommand(command, canExecute), PropertySetModes.SetAsOriginal, propertyName);

			return Get<DelegateCommand>(propertyName);
		}

		/// <summary>
		/// Returns an ICommand wrapped around the provided action.
		/// </summary>
		/// <param name="propertyName"></param>
		/// <param name="command"></param>
		/// <param name="canExecute"></param>
		/// <returns></returns>
		protected DelegateCommand GetCommand(Action command, Func<bool> canExecute, [CallerMemberName] string propertyName)
		{
			if (command == null)
				throw new ArgumentNullException("command", "command is null.");
			if (propertyName == null)
				throw new ArgumentNullException("propertyName", "propertyName is null");
			if (String.IsNullOrEmpty(propertyName))
				throw new ArgumentException("propertyName is empty", "propertyName");
			Contract.EndContractBlock();

			if (!Properties.IsDefined(propertyName))
				Properties.Set(new DelegateCommand(command, canExecute), PropertySetModes.SetAsOriginal, propertyName);

			return Get<DelegateCommand>(propertyName);
		}

	}
}
